
#ifndef ANDROID_GLTEST_FRAMEQUEUE_H
#define ANDROID_GLTEST_FRAMEQUEUE_H

//#include <queue>
//#include <atomic>
//#include <thread>
//#include <condition_variable>

#include <utils/Condition.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>

#include "Queue.h"


namespace android {

        // BufferState represents the different states in which a buffer slot
        // can be.  All slots are initially FREE.
        enum BufferState {
            INVALID = -1,

            // FREE indicates that the buffer is available to be dequeued
            // by the producer.  The buffer may be in use by the consumer for
            // a finite time, so the buffer must not be modified until the
            // associated fence is signaled.
            //
            // The slot is "owned" by BufferQueue.  It transitions to DEQUEUED
            // when dequeueBuffer is called.
            FREE = 0,

            // DEQUEUED indicates that the buffer has been dequeued by the
            // producer, but has not yet been queued or canceled.  The
            // producer may modify the buffer's contents as soon as the
            // associated ready fence is signaled.
            //
            // The slot is "owned" by the producer.  It can transition to
            // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
            DEQUEUED = 1,

            // QUEUED indicates that the buffer has been filled by the
            // producer and queued for use by the consumer.  The buffer
            // contents may continue to be modified for a finite time, so
            // the contents must not be accessed until the associated fence
            // is signaled.
            //
            // The slot is "owned" by BufferQueue.  It can transition to
            // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
            // queued in asynchronous mode).
            QUEUED = 2,

            // ACQUIRED indicates that the buffer has been acquired by the
            // consumer.  As with QUEUED, the contents must not be accessed
            // by the consumer until the fence is signaled.
            //
            // The slot is "owned" by the consumer.  It transitions to FREE
            // when releaseBuffer is called.
            ACQUIRED = 3
        };

    struct BufferSlot {

        // mBufferState is the current state of this buffer slot.
        BufferState mBufferState;

        // the index of this buffer slot
        uint32_t mSlotId;

        // the actual data
        uint8_t* mBufferPtr;
    };


class FrameQueue : public virtual RefBase {

public:
    enum { NUM_BUFFER_SLOTS = 4 };

    FrameQueue(int, int, int);
    ~FrameQueue();

    int getFrameSize() {
        return mWidth * mHeight * mBPP / 8;
    }

//    status_t setFrameFormat(int width, int height, int bpp);

    // setBufferCount updates the number of available buffer slots.
    // This may only be called by the producer.
    //virtual status_t setBufferCount(int count);

    // dequeueBuffer gets the next buffer slot index for the producer to use.
    // If a buffer slot is available then that slot index is written to the 
    // location pointer to by the buf argument and a status of OK is returned.
    // If no slot is available then a status of -EBUSY is returned and buf is
    // unmodified.
    // This may only be called by the producer.
    status_t dequeueBuffer(int *idx, void** ptr);
    
    // queueBuffer returns a filled buffer to the Queue.
    // This may only be called by the producer.
    status_t queueBuffer(int buf);

    // acquireBuffer attemps to acquire ownership of the next pending buffer in 
    // the Queue.
    // If a buffer is successfully acquired, the slot index is written to the
    // location pointer to by the buf argument and a status of OK is returned.
    // If no buffer is pending then it returns -EINVAL.
    // This may only be called by the consumer.
    status_t acquireBuffer(int *idx, void** ptr);

    // releaseBuffer releases a buffer slot from the consumer back to the Queue.
    // This may only be called by the consumer.
    status_t releaseBuffer(int buf);


private:

    // a slot --> a buffer
    BufferSlot mSlots[NUM_BUFFER_SLOTS];

    // mDefaultWidth holds the default width of allocated buffers. It is used
    // if actual width and height is not specified.
    uint32_t mWidth;

    // mDefaultHeight holds the default height of allocated buffers. It is used
    // if actual width and height is not specified.
    uint32_t mHeight;

    // bits-per-pixel
    uint32_t mBPP;

    // memory handler
    void* mPtr;


//    mutable std::mutex mMutex;
//    std::condition_variable mCond;
//    std::queue<BufferSlot> mFreeQueue;  // FREE, to be dequeued by producer
//    std::queue<BufferSlot> mReadyQueue; // QUEUED, to be acquired by consumer

    mutable Mutex mMutex;
    Condition mCond;
    Queue<BufferSlot> mFreeQueue;
    Queue<BufferSlot> mReadyQueue;

    // get mSlots[idx]
    BufferSlot& getBufferSlotLocked(int idx);

    // free memory
    status_t freeBufferSlot();

    // allocate memory
    status_t initBufferSlot();

};




}  // namespace

#endif  // ANDROID_GLTEST_FRAMEQUEUE_H
